package it.gtd.swimpool.model.entity;

import com.google.common.annotations.Beta;
import com.google.common.annotations.VisibleForTesting;

import javax.persistence.*;
import java.util.Date;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

@Entity
@Table(name = "feedbacks")
@NamedQueries({
    @NamedQuery(
        name = "Feedback.byTarget",
        query = "SELECT feedback FROM Feedback AS feedback WHERE feedback.composed.target = :target"),
    @NamedQuery(
        name = "Feedback.byTargetAndSkill",
        query = "SELECT feedback FROM Feedback AS feedback WHERE feedback.composed.target = :target AND feedback.composed.skill = :skill"),
    @NamedQuery(
        name = "Feedback.authorsForSkillAndTarget",
        query = "SELECT feedback.composed.author FROM Feedback AS feedback WHERE feedback.composed.target = :target AND feedback.composed.skill = :skill"
    )
})
@Beta
public class Feedback {
    @EmbeddedId
    private FeedbackId composed;

    @Enumerated(EnumType.ORDINAL)
    private Rating rating;

    @Basic(optional = true)
    private String text;
    @VisibleForTesting
    static final int MAX_TEXT_LENGTH = 255;

    public Feedback() {
    }

    public Feedback(User author, User target, Skill skill) {
        this();

        checkNotNull(author, "author can't be null");
        checkNotNull(target, "target can't be null");
        checkNotNull(skill, "skill can't be null");

        this.composed = this.composed == null ? new FeedbackId() : this.composed;
        this.composed.setAuthor(author);
        this.composed.setTarget(target);
        this.composed.setSkill(skill);
        this.setRating(Rating.OneStar);
    }

    public Date getCreationeDate() {
        return composed.getCreationDate();
    }

    public User getAuthor() {
        return composed.getAuthor();
    }

    public User getTarget() {
        return composed.getTarget();
    }

    public Skill getSkill() {
        return composed.getSkill();
    }

    public Rating getRating() {
        return rating;
    }

    public void setRating(Rating rating) {
        checkNotNull(rating, "rating can't be null");

        this.rating = rating;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        checkNotNull(text, "text can't be null");
        checkArgument(!text.isEmpty(), "Feedback text can't be empty");
        checkArgument(text.length() < MAX_TEXT_LENGTH, "Feedback text can't be longer than " + MAX_TEXT_LENGTH);

        this.text = text;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Feedback)) return false;

        Feedback feedback = (Feedback) o;

        if (composed != null ? !composed.equals(feedback.composed) : feedback.composed != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return composed != null ? composed.hashCode() : 0;
    }
}

